package com.catazy.album.presentation.screen.albumdetail

import androidx.compose.runtime.Immutable
import androidx.lifecycle.viewModelScope
import com.catazy.album.domain.model.Album
import com.catazy.album.domain.model.Tag
import com.catazy.album.domain.model.Track
import com.catazy.base.domain.result.Result
import com.catazy.album.domain.usecase.GetAlbumUseCase
import com.catazy.base.presentation.viewmodel.BaseAction
import com.catazy.base.presentation.viewmodel.BaseState
import com.catazy.base.presentation.viewmodel.BaseViewModel
import com.catazy.album.presentation.screen.albumdetail.AlbumDetailViewModel.UiState
import com.catazy.album.presentation.screen.albumdetail.AlbumDetailViewModel.UiState.Loading
import com.catazy.album.presentation.screen.albumdetail.AlbumDetailViewModel.Action
import kotlinx.coroutines.launch

/**
 * 作者: Tao
 * 日期: 2024/12/24
 * 时间: 10:21
 * 描述: AlbumDetailViewModel 是负责处理专辑详情页面逻辑的 ViewModel。
 *          它继承自 BaseViewModel，用于管理 UI 状态和处理用户操作。
 *          @param getAlbumUseCase 用于获取专辑信息的用例
 *
 *
 * @Immutable
 *  用于标记一个类或接口为不可变的，确保其状态一旦创建后不会改变
 * 密封接口 (sealed interface)
 *  密封接口允许您定义一组受限的子类型，确保所有可能的状态都在定义范围内
 * 数据类 (data class)
 *  Content: 表示内容加载成功时的状态
 *  Loading 和 Error: 分别表示加载中和错误状态。使用 data object 确保这些状态是单例的
 */
internal class AlbumDetailViewModel(
    private val getAlbumUseCase: GetAlbumUseCase
) :
    BaseViewModel<UiState, Action>(Loading) {

    /**
     * 当进入专辑详情页面时调用此方法。
     * 它通过传递 AlbumDetailFragmentArgs 来加载专辑信息。
     * @param args 专辑详情页面的参数，包含专辑的相关信息
     */
    fun onEnter(args: AlbumDetailFragmentArgs) {
        getAlbum(args)
    }

    /**
     * 根据参数获取专辑信息，并根据结果更新 UI 状态。
     * 此方法在 ViewModel 的作用域内异步执行。
     * @param args 专辑详情页面的参数，包含专辑的相关信息
     */
    private fun getAlbum(args: AlbumDetailFragmentArgs) {
        viewModelScope.launch {
            getAlbumUseCase(args.artistName, args.albumName, args.mbId).also {
                when (it) {
                    is Result.Success -> {
                        sendAction(Action.AlbumLoadSuccess(it.data))
                    }

                    is Result.Failure -> {
                        sendAction(Action.AlbumLoadFailure)
                    }
                }
            }
        }
    }

    /**
     * 定义了一个密封接口 Action，用于表示不同的操作，并且这些操作可以改变 UI 状态 (UiState)
     */
    internal sealed interface Action : BaseAction<UiState> {

        /**
         * 专辑加载成功时的操作
         * 包含一个私有属性 album，并实现了 reduce 方法来更新 UiState
         */
        data class AlbumLoadSuccess(private val album: Album) : Action {
            override fun reduce(state: UiState): UiState {
                return UiState.Content(
                    albumName = album.name,
                    artistName = album.artist,
                    coverImageUrl = album.getDefaultImageUrl() ?: "",
                    tracks = album.tracks.orEmpty(),
                    tags = album.tags.orEmpty(),
                )
            }
        }

        /**
         * 专辑加载失败时的操作
         * 使用 data object 确保这是一个单例对象，并实现了 reduce 方法来返回错误状态
         */
        data object AlbumLoadFailure : Action {
            override fun reduce(state: UiState): UiState {
                return UiState.Error
            }
        }
    }

    @Immutable
    internal sealed interface UiState : BaseState {
        /**
         * 内容加载成功时的状态。
         * @param albumName 专辑名称
         * @param artistName 艺术家名称
         * @param coverImageUrl 封面图片URL
         * @param tracks 曲目列表
         * @param tags 标签列表
         */
        data class Content(
            val albumName: String = "",
            val artistName: String = "",
            val coverImageUrl: String = "",
            val tracks: List<Track> = emptyList(),
            val tags: List<Tag> = emptyList(),
        ) : UiState

        /**
         * 加载中的状态。
         */
        data object Loading : UiState

        /**
         * 错误状态。
         */
        data object Error : UiState
    }
}